
#include "threadpool.h"
#include <shadow.h>
int exitpipe[2];

//********************************************************************************
//信号处理函数，通知子进程退出
//********************************************************************************
void sigfunc(int num) 
{
    printf("sig %d is coming\n", num);
    //通过管道通知父进程退出
    char ch = 1;
    write(exitpipe[1], &ch, 1);
}

//********************************************************************************
//指令错误函数，向对端发送信息，告知指令错误
//********************************************************************************
void senderror(int fd)
{
    send(fd,"false command!",strlen("false command!"),0);
}

//********************************************************************************
//用户验证
//********************************************************************************
void get_salt(char *salt,char *passwd) {
    int i,j;
    //取出 salt,i 记录密码字符下标,j 记录$出现次数
    for(i=0,j=0;passwd[i] && j != 3;++i) {
        if(passwd[i] == '$') ++j;
    }
    strncpy(salt,passwd,i-1);
}
//********************************************************************************
//主函数
//********************************************************************************
int main(int argc, char *argv[])
{
    // ./server ip,port,processNum

    ARGS_CHECK(argc, 4);
    int threadNum = atoi(argv[3]);
    pipe(exitpipe);//创建退出的管道

    pid_t pid = fork();
    if(pid > 0) {
        signal(SIGUSR1, sigfunc);//10号信号
        close(exitpipe[0]);
        wait(NULL);
        exit(0);
    }
    //子进程
    close(exitpipe[1]);
    thread_pool_t threadpool;
    threadpoolInit(&threadpool, threadNum);
    threadpoolStart(&threadpool);

    //2. 创建TCP的监听套接字listenfd
    int listenfd = tcpInit(argv[1], atoi(argv[2]));

    //3. 创建epoll的实例, 并注册(监听)相应文件描述符上的事件
    int epfd =  epoll_create1(0);
    ERROR_CHECK(epfd, -1, "epoll_create1");
    epollAddReadEvent(epfd, listenfd);
    epollAddReadEvent(epfd, exitpipe[0]);

    struct epoll_event * pevtList = (struct epoll_event*)
        calloc(MAXCONNS, sizeof(struct epoll_event));

    int nready;
    while(1) {
        do {
            //4. epoll等待事件就绪
            nready = epoll_wait(epfd, pevtList, MAXCONNS, -1);
        }while(-1 == nready && errno == EINTR);

        if(0 == nready) {
            printf(">> epoll timeout.\n");
            continue;
        } else if(-1 == nready) {
            perror("epoll_wait");
            return EXIT_FAILURE;
        } else {//nready > 0

            for(int i = 0; i < nready; ++i) {
                int fd = pevtList[i].data.fd;
                if(fd == listenfd) {//5. 客户端到来的处理
                    int peerfd = accept(listenfd, NULL, NULL);
                    if(peerfd < 0) {
                        perror("accept");
                    }
                    printf("accept a new conn, peerfd: %d\n", peerfd);
                    //while(1){
                    //    //验证用户
                    //    char name[26] = {0};
                    //    char key[64] = {0};
                    //    int namelen;
                    //    int keylen;
                    //    recv(peerfd, &namelen, 4, MSG_WAITALL);
                    //    recvCircle(peerfd, name, namelen);
                    //    printf("name:%s\n", name);
                    //    recv(peerfd, &keylen, 4, MSG_WAITALL);
                    //    recvCircle(peerfd, key, keylen);
                    //    printf("key:%s\n", key);
                    //    struct spwd *sp;
                    //    char salt[512] = {0};
                    //    sp = getspnam(name);
                    //    get_salt(salt,sp->sp_pwdp);
                    //    char sucessmsg[100] = "登陆成功!\n";
                    //    char failmsg[100] = "用户名或密码错误，请重新登录\n";
                    //    train_t confirm;
                    //    if(strcmp((sp->sp_pwdp), crypt(key, salt)) == 0){
                    //        memset(&confirm, 0, sizeof(confirm));
                    //        confirm.len = strlen(sucessmsg);
                    //        strcpy(confirm.data, sucessmsg);
                    //        send(peerfd, &confirm, 4 + confirm.len, MSG_WAITALL);
                    //        printf("%s\n", confirm.data);
                    //        //监听新连接
                            epollAddReadEvent(epfd, peerfd);
                            printf("监听新连接成功\n");
                    //        break;
                    //    }else{
                    //        memset(&confirm, 0, sizeof(confirm));
                    //        confirm.len = strlen(failmsg);
                    //        strcpy(confirm.data, failmsg);
                    //        send(peerfd, &confirm, 4 + confirm.len, MSG_WAITALL);
                    //        printf("%s\n", confirm.data);
                    //        continue;
                    //    }

                    //}
                } else if(fd == exitpipe[0]) {
                    //退出信号
                    char exitflag;
                    read(exitpipe[0], &exitflag, 1);
                    printf("parent process ready to exit.\n");
                    //收到退出的通知之后，子线程要逐步退出
                    queueWakeup(&threadpool.queue);
                    for(int j = 0; j < threadNum; ++j) {
                        pthread_join(threadpool.threads[j], NULL);
                    }
                    printf("parent process pool exit\n");
                    threadpoolDestroy(&threadpool);
                    exit(0);
                } 
                else{//旧连接的信号
                    printf("connect a new CMD\n");
                    printf("peerfd = %d\n",fd);
                    //取指令

                    task_t* ptask = recvCmd(fd);

                    //指令加入任务队列
                    taskEnqueue(&threadpool.queue,ptask);
                }
            }
        }
    }

    free(pevtList); 
    close(listenfd);
    close(epfd);
    return 0;
}
